﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace PcArduinoControl
{
	abstract class Packet
	{
		internal const byte cStartByte = 0xE0;
		internal const byte cTerminatorByte = 0xEF;
		internal const byte cLimit = 0xE0;
		internal const byte cUnassignedId = cLimit;

		public byte Id { get; internal set; }
		public Direction Direction { get; private set; }
		public byte[] Data { get; protected set; }

		public byte CalculatedChecksum
		{
			get
			{
				byte checksum = Id;

				foreach (byte b in Data)
					checksum = (byte)((checksum + b) % cLimit);

				return checksum;
			}
		}

		public abstract byte StatedChecksum { get; }

		internal Packet(Direction direction) :
			this(direction, new byte[0])
		{
		}

		internal Packet(byte id, Direction direction) :
			this(id, direction, new byte[0])
		{
		}

		internal Packet(Direction direction, params byte[] data) :
			this(cUnassignedId, direction, data)
		{
		}

		internal Packet(byte id, Direction direction, params byte[] data)
		{
			Id = id;
			Direction = direction;
			Data = data;
		}

		public byte[] ToByteArray()
		{
			Stack<byte> buffer = new Stack<byte>();

			// Push start byte.
			buffer.Push(cStartByte);

			// Push Id.
			buffer.Push(Id);

			// Push data.
			foreach (byte b in Data)
				buffer.Push(b);

			// Push terminator byte.
			buffer.Push(cTerminatorByte);

			// Push checksum
			buffer.Push(StatedChecksum);

			return buffer.Reverse().ToArray();
		}
	}
}
